package kmi.droid.livewallpaper.gl;

import javax.microedition.khronos.opengles.GL;

import kmi.droid.livewallpaper.gl.EGLFactory.EGLContextFactory;
import kmi.droid.livewallpaper.gl.EGLFactory.EGLWindowSurfaceFactory;
import android.service.wallpaper.WallpaperService;
import android.util.Log;
import android.view.SurfaceHolder;

public class GLWallpaperService extends WallpaperService
{
	private static final String TAG = "GLWallpaperService";

	@Override
	public Engine onCreateEngine()
	{
		return new GLEngine();
	}

	public class GLEngine extends Engine
	{
		public final static int RENDERMODE_WHEN_DIRTY = 0;
		public final static int RENDERMODE_CONTINUOUSLY = 1;

		private GLWrapper _glWrapper;
		private GLPaintingThread _glThread;

		private EGLConfigChooserBase _eglConfigChooser;
		private EGLContextFactory _eglContextFactory;
		private EGLWindowSurfaceFactory _eglWindowSurfaceFactory;

		private int _debugFlags;

		@Override
		public void onVisibilityChanged(boolean visible)
		{
			if (visible)
				onResume();
			else
				onPause();

			super.onVisibilityChanged(visible);
		}

		@Override
		public void onCreate(SurfaceHolder surfaceHolder)
		{
			super.onCreate(surfaceHolder);
			// Log.d(TAG, "GLEngine.onCreate()");
		}

		@Override
		public void onDestroy()
		{
			super.onDestroy();
			// Log.d(TAG, "GLEngine.onDestroy()");
			_glThread.requestExitAndWait();
		}

		@Override
		public void onSurfaceChanged(SurfaceHolder holder, int format,
				int width, int height)
		{
			// Log.d(TAG, "onSurfaceChanged()");
			_glThread.onWindowResize(width, height);
			super.onSurfaceChanged(holder, format, width, height);
		}

		@Override
		public void onSurfaceCreated(SurfaceHolder holder)
		{
			Log.d(TAG, "onSurfaceCreated()");
			_glThread.surfaceCreated(holder);
			super.onSurfaceCreated(holder);
		}

		@Override
		public void onSurfaceDestroyed(SurfaceHolder holder)
		{
			Log.d(TAG, "onSurfaceDestroyed()");
			_glThread.surfaceDestroyed();
			super.onSurfaceDestroyed(holder);
		}

		public void setGLWrapper(GLWrapper glWrapper)
		{
			_glWrapper = glWrapper;
		}

		public void setDebugFlags(int debugFlags)
		{
			_debugFlags = debugFlags;
		}

		public int getDebugFlags()
		{
			return _debugFlags;
		}

		public void setRenderer(GLRenderer renderer)
		{
			checkRenderThreadState();

			if (_eglConfigChooser == null)
				_eglConfigChooser = new EGLConfigChooserBase.SimpleEGLConfigChooser(
						true);

			if (_eglContextFactory == null)
				_eglContextFactory = new EGLFactory.DefaultContextFactory();

			if (_eglWindowSurfaceFactory == null)
				_eglWindowSurfaceFactory = new EGLFactory.DefaultWindowSurfaceFactory();

			_glThread = new GLPaintingThread(renderer, _eglConfigChooser,
					_eglContextFactory, _eglWindowSurfaceFactory, _glWrapper);

			_glThread.start();
		}

		public void setEGLContextFactory(EGLContextFactory factory)
		{
			checkRenderThreadState();
			_eglContextFactory = factory;
		}

		public void setEGLWindowSurfaceFactory(EGLWindowSurfaceFactory factory)
		{
			checkRenderThreadState();
			_eglWindowSurfaceFactory = factory;
		}

		public void setEGLConfigChooser(EGLConfigChooserBase configChooser)
		{
			checkRenderThreadState();
			_eglConfigChooser = configChooser;
		}

		public void setEGLConfigChooser(boolean needDepth)
		{
			setEGLConfigChooser(new EGLConfigChooserBase.SimpleEGLConfigChooser(
					needDepth));
		}

		public void setEGLConfigChooser(int redSize, int greenSize,
				int blueSize, int alphaSize, int depthSize, int stencilSize)
		{
			setEGLConfigChooser(new EGLConfigChooserBase.ComponentSizeChooser(
					redSize, greenSize, blueSize, alphaSize, depthSize,
					stencilSize));
		}

		public void setRenderMode(int renderMode)
		{
			_glThread.setRenderMode(renderMode);
		}

		public int getRenderMode()
		{
			return _glThread.getRenderMode();
		}

		public void requestRender()
		{
			_glThread.requestRender();
		}

		public void onPause()
		{
			_glThread.onPause();
		}

		public void onResume()
		{
			_glThread.onResume();
		}

		public void queueEvent(Runnable r)
		{
			_glThread.queueEvent(r);
		}

		private void checkRenderThreadState()
		{
			if (_glThread != null)
			{
				throw new IllegalStateException(
						"setRenderer has already been called for this instance.");
			}
		}
	}
}

/**
 * An interface for customizing the eglCreateWindowSurface and eglDestroySurface
 * calls.
 * 
 * This interface must be implemented by clients wishing to call
 * {@link GLWallpaperService#setEGLWindowSurfaceFactory(EGLWindowSurfaceFactory)}
 */

interface GLWrapper
{
	GL wrap(GL gl);
}
